using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Dude_Platformer.Weapon;

namespace Dude_Platformer
{
    /// <summary>
    /// Our fearless adventurer!
    /// </summary>
    public class Player : Entity
    {
        // Animations
        private Animation idleAnimation;
        private Animation runAnimation;
        private Animation celebrateAnimation;

        private Animation crouchAnimation;
        private SpriteEffects flip = SpriteEffects.None;

        // Sounds
        private SoundEffect killedSound;
        private SoundEffect fallSound;

        // weapons
        public const GunType DEFAULT_GUN_TYPE = GunType.MAVERICK;

        //// Crouching state
        //public Boolean IsCrouching
        //{
        //    get { return isCrouching; }
        //}
        // Crouching state
        private Boolean isCrouching;

        private Rectangle localBounds;

        /// <summary>
        /// Constructors a new player.
        /// </summary>
        public Player(Level level, Vector2 position)
            : base(level)
        {
            LoadContent();
            Reset(position);
        }

        /// <summary>
        /// Loads the player sprite sheet and sounds.
        /// </summary>
        public void LoadContent()
        {
            // Load animated textures.
            idleAnimation = new Animation(myLevel.Content.Load<Texture2D>("Sprites/Player/Idle"), 0.1f, true);
            runAnimation = new Animation(myLevel.Content.Load<Texture2D>("Sprites/Player/Run"), 0.1f, true);
            jumpAnimation = new Animation(myLevel.Content.Load<Texture2D>("Sprites/Player/Jump"), 0.1f, false);
            celebrateAnimation = new Animation(myLevel.Content.Load<Texture2D>("Sprites/Player/Celebrate"), 0.1f, false);
            dieAnimation = new Animation(myLevel.Content.Load<Texture2D>("Sprites/Player/Die"), 0.1f, false);
            crouchAnimation = new Animation(myLevel.Content.Load<Texture2D>("Sprites/Player/Crouch"), 0.1f, false);


            string str = "Sprites/Player/Idle";
            switch (myLevel.LevelID)
            {
                case 0: str = "Sprites/Player/Shoot_Stinger";
                    gun = new Gun(GunType.STINGER);
                    break;
                case 1: str = "Sprites/Player/Shoot_Maverick";
                    gun = new Gun(GunType.MAVERICK);
                    break;
                case 2: str = "Sprites/Player/Shoot_super";
                    gun = new Gun(GunType.SUPER);
                    break;
            }
            shootAnimation = new Animation(myLevel.Content.Load<Texture2D>(str), 0.1f, true);

            // Calculate bounds within texture size.            
            int width = (int)(idleAnimation.FrameWidth * 0.4);
            int left = (idleAnimation.FrameWidth - width) / 2;
            int height = (int)(idleAnimation.FrameWidth * 0.8);
            int top = idleAnimation.FrameHeight - height;
            localBounds = new Rectangle(left, top, width, height);

            // Load sounds.            
            killedSound = myLevel.Content.Load<SoundEffect>("Sounds/PlayerKilled");
            jumpSound = myLevel.Content.Load<SoundEffect>("Sounds/PlayerJump");
            fallSound = myLevel.Content.Load<SoundEffect>("Sounds/PlayerFall");
        }

        /// <summary>
        /// Resets the player to life.
        /// </summary>
        /// <param name="position">The position to come to life at.</param>
        public void Reset(Vector2 position)
        {
            hp = getBasicHp();
            this.position = position;
            this.velocity = Vector2.Zero;
            isAlive = true;
            sprite.PlayAnimation(idleAnimation);
            gun.Reset();
        }

        /// <summary>
        /// Handles input, performs physics, and animates the player sprite.
        /// </summary>
        public void Update(GameTime gameTime)
        {
            GetInput();

            ApplyPhysics(gameTime);

            if (IsAlive && IsOnGround)
            {
                if (Math.Abs(Velocity.X) - 0.02f > 0)
                {
                    sprite.PlayAnimation(runAnimation);
                }
                else if (isCrouching)
                {
                    sprite.PlayAnimation(crouchAnimation);
                }
                else if (isShooting)
                {
                    sprite.PlayAnimation(shootAnimation);
                }
                else
                {
                    sprite.PlayAnimation(idleAnimation);
                }
            }

            // Clear input.
            movement = 0.0f;
            isJumping = false;
        }

        /// <summary>
        /// Gets player horizontal movement and jump commands from input.
        /// </summary>
        private void GetInput()
        {
            // Get input state.
            GamePadState gamePadState = GamePad.GetState(PlayerIndex.One);
            KeyboardState keyboardState = Keyboard.GetState();

            // Get analog horizontal movement.
            movement = gamePadState.ThumbSticks.Left.X * MoveStickScale;

            // Ignore small movements to prevent running in place.
            if (Math.Abs(movement) < 0.5f)
                movement = 0.0f;
            isShooting = false;

            // Check if the player wants to crouch and if it does i cannont move in any other way.
            if (keyboardState.IsKeyDown(Keys.S) || keyboardState.IsKeyDown(Keys.Down))
            {
                isCrouching = true;
            }
            else
            {
                isCrouching = false;

                // If any digital horizontal movement input is found, override the analog movement.
                if (gamePadState.IsButtonDown(Buttons.DPadLeft) ||
                    keyboardState.IsKeyDown(Keys.Left) ||
                    keyboardState.IsKeyDown(Keys.A))
                {
                    movement = -1.0f;
                }
                else if (gamePadState.IsButtonDown(Buttons.DPadRight) ||
                         keyboardState.IsKeyDown(Keys.Right) ||
                         keyboardState.IsKeyDown(Keys.D))
                {
                    movement = 1.0f;
                }

                // Check if the player wants to jump.
                isJumping =
                    gamePadState.IsButtonDown(JumpButton) ||
                    keyboardState.IsKeyDown(Keys.Space) ||
                    keyboardState.IsKeyDown(Keys.Up) ||
                    keyboardState.IsKeyDown(Keys.W);
            }

            if (gamePadState.IsButtonDown(Buttons.A) ||
                         keyboardState.IsKeyDown(Keys.Q))
            {
                if (isCrouching)
                {
                    // No firing
                    // bulletPosition.Y -= Tile.Height * .5f;
                    // gun.Fire(level, bulletPosition, flip == SpriteEffects.None ? FaceDirection.Left : FaceDirection.Right);
                }
                else
                {
                    isShooting = true;
                    gun.Fire(myLevel, AmmoType.PlayerAmmo, this.position, Direction);
                }
            }

            if (gamePadState.IsButtonDown(Buttons.B) ||
                         keyboardState.IsKeyDown(Keys.R))
            {
                gun.Reload();
            }
        }

        /// <summary>
        /// Called when the player has been killed.
        /// </summary>
        /// <param name="killedBy">
        /// The enemy who killed the player. This parameter is null if the player was
        /// not killed by an enemy (fell into a hole).
        /// </param>
        public void OnKilled(Boolean falling)
        {
            if (falling)
            {
                isAlive = false;
                fallSound.Play();
            }
            else
            {
                isAlive = false;
                killedSound.Play();
                sprite.PlayAnimation(dieAnimation);
            }

        }

        /// <summary>
        /// Called when this player reaches the level's exit.
        /// </summary>
        public void OnReachedExit()
        {
            sprite.PlayAnimation(celebrateAnimation);
        }

        /// <summary>
        /// Draws the animated player.
        /// </summary>
        public void Draw(GameTime gameTime, SpriteBatch spriteBatch)
        {
            // Flip the sprite to face the way we are moving.
            if (Velocity.X > 0)
            {
                Direction = FaceDirection.Right;
                flip = SpriteEffects.FlipHorizontally;
            }
            else if (Velocity.X < 0)
            {
                Direction = FaceDirection.Left;
                flip = SpriteEffects.None;
            }
            // Draw that sprite.
            sprite.Draw(gameTime, spriteBatch, Position, flip);
        }

        override protected GunType getDefaultGunType()
        {
            return GunType.MAVERICK;
        }

        protected override int getBasicHp()
        {
            return 5;
        }

        protected override void updateRectangles()
        {
            int left = (int)Math.Round(Position.X - sprite.Origin.X) + localBounds.X;
            int top = (int)Math.Round(Position.Y - sprite.Origin.Y) + localBounds.Y;
            if (isCrouching)
            {
                left -= 20;
                myBoundingRectangle = new Rectangle(left, top, localBounds.Width + 40, localBounds.Height);
            }
            else
            {
                myBoundingRectangle = new Rectangle(left, top, localBounds.Width, localBounds.Height);
            }
        }

        internal void touch(Ammo ammo)
        {
            if (!ammo.explode)
            {
                ammo.explode = true;
                if ((ammo.Direction != Direction) && (isCrouching))
                {
                }
                else
                {
                    hp -= ammo.Damage;
                    if (hp <= 0)
                    {
                        OnKilled(false);
                    }
                }
            }
        }
    }
}
